const obj3 = {
    a: 3,
    b: {
        obj1: "obj1", //这里最终要放入obj1
    },
};
const obj2 = {
    a: 2,
    [Symbol("b")]: "2b",
    obj3: obj3,
};
const obj1 = {
    a: new Map([[1, 2], [2, { a: 1 }]]),
    b: new Set([1, 2, 3]),
    // get c() {
    //     return "1c";
    // },
    obj2: obj2,
};
const obj = {
    out: "out",
    obj1: "obj1", //这里最终要放入obj1
};
obj3.b.obj1 = obj1;
obj.obj1 = obj1;
/**深拷贝。支持循环引用、map、set、Date、RegExp、Function。
 * - 缺点：function无法保留作用域，不支持Symbol深拷贝 */
export default function deepClone(target) {
    /**防止循环引用的map */
    const cache = new WeakMap();
    function clone(data) {
        // 基础类型直接返回值
        if (!((typeof data === 'object' && data) || typeof data === 'function')) {
            return data;
        }
        // 如果该对象已存在，则直接返回该对象 
        if (cache.has(data)) {
            return cache.get(data);
        }
        // 日期或者正则对象则直接构造一个新的对象返回
        if ([Date, RegExp].includes(data.constructor)) {
            return new data.constructor(data);
        }
        // 处理函数对象
        if (typeof data === 'function') {
            return new Function('return ' + data.toString())();
        }
        // 处理Map对象
        if (data instanceof Map) {
            const result = new Map();
            cache.set(data, result);
            data.forEach((val, key) => {
                result.set(key, clone(val));
            });
            return result;
        }
        // 处理Set对象
        if (data instanceof Set) {
            const result = new Set();
            cache.set(data, result);
            data.forEach(val => {
                result.add(clone(val));
            });
            return result;
        }
        const keys = Reflect.ownKeys(data); // 收集键名（考虑了以Symbol作为key以及不可枚举的属性） 
        const allDesc = Object.getOwnPropertyDescriptors(data); // 利用 Object 的 getOwnPropertyDescriptors 方法可以获得对象的所有属性以及对应的属性描述
        const result = Object.create(Object.getPrototypeOf(data), allDesc); //继承data的原型，并且浅拷贝allDesc
        // 新对象加入到map中，进行记录 （需要线缓存，再进行下面的操作）
        cache.set(data, result);
        // Object.create()是浅拷贝，所以要判断并递归执行深拷贝
        keys.forEach(key => {
            result[key] = clone(data[key]);
        });
        return result;
    }
    return clone(target);
}
/**循环引用的对象 */
export const circulateObj = obj;
const newObj = deepClone(circulateObj);
console.log('原', circulateObj);
console.log('新', newObj);
console.log('是否相同', newObj === circulateObj);
console.log('修改——————————');
circulateObj.obj1.obj2.obj3.a = 666;
circulateObj.obj1.b.delete(1);
circulateObj.obj1.a.set(2, 2);
console.log('原', circulateObj);
console.log('新', newObj);
console.log('是否相同', newObj === circulateObj);
